import 'dart:io';

import 'package:get/get.dart';
import 'package:hive/hive.dart';
import 'package:path_provider/path_provider.dart';
import 'package:toolbox/manager/tools.dart';
import 'package:toolbox/models/FetchWebsiteInfoModel.dart';
import 'package:toolbox/models/TranslateModel.dart';
import 'package:toolbox/models/WebBookmarkModel.dart';
import 'package:toolbox/page/browser/browser_logic.dart';
import 'package:toolbox/page/browser/browser_state.dart';

class HiveHelper {
  static HiveHelper get instance => _getInstance();
  static HiveHelper? _instance;
  HiveHelper._();
  static HiveHelper _getInstance() {
    _instance ??= HiveHelper._();
    return _instance!;
  }

  Box? _translateHistoryBox;
  Box? get translateHistoryBox => _translateHistoryBox;
  static const String _translateHistoryKey = 'TranslateHistoryBox';

  Box? _webStarBox;
  Box? get webBox => _webStarBox;
  static const String _webStarKey = 'WebStarBox';
  static const String _webHistoryKey = 'WebHistoryBox';

  Box? _fetchWebsiteInfoBox;
  Box? get fetchWebsiteInfoBox => _fetchWebsiteInfoBox;
  static const String _fetchWebsiteInfoKey = 'FetchWebsiteInfoKey';

  Box? _settingBox;
  static const String _webHomePageUrlKey = 'WebHomePageUrlKey';
  static const String _webHomePageCustomUrlListKey = 'WebHomePageCustomUrlListKey';

  static Future<void> init() async {
    Directory directory = await getApplicationDocumentsDirectory();
    Hive.init(directory.path);

    Hive.registerAdapter(TranslateModelAdapter());
    _getInstance()._translateHistoryBox = await Hive.openBox('translateBox');

    Future<String?> getHivePath(String filename) async {
      String dir = directory.path;
      Directory _directory = Directory('$dir/hive/');
      try {
        if (!_directory.existsSync()) {
          _directory.createSync(recursive: true);
          if (!_directory.existsSync()) {
            return null;
          }
        }
        return '${_directory.path}$filename';
      } on Exception catch (e) {
        return null;
      }
    }
    
    try {
      String boxName = 'settingBox';
      String? boxPath = await getHivePath(boxName);
      if (boxPath != null && boxPath.isNotEmpty) {
        _getInstance()._settingBox = await Hive.openBox(boxName, path: boxPath);
      }
    } catch (e) {
      print(e);
    }

    try {
      Hive.registerAdapter(WebBookmarkModelAdapter());
      String boxName = 'webStarBox';
      String? boxPath = await getHivePath(boxName);
      if (boxPath != null && boxPath.isNotEmpty) {
        _getInstance()._webStarBox = await Hive.openBox(boxName, path: boxPath);
      }
    } catch (e) {
      print(e);
    }

    try {
      Hive.registerAdapter(FetchWebsiteInfoModelAdapter());
      String boxName = 'fetchWebsiteInfoBox';
      String? boxPath = await getHivePath(boxName);
      if (boxPath != null && boxPath.isNotEmpty) {
        _getInstance()._fetchWebsiteInfoBox = await Hive.openBox(boxName, path: boxPath);
      }
    } catch (e) {
      print(e);
    }
  }

  Future<void> _set(String key, dynamic value) async {
    return _settingBox?.put(key, value);
  }

  dynamic _get(String key, {dynamic defaultValue}) {
    return _settingBox?.get(key, defaultValue: defaultValue);
  }

  void saveTranslateHistory(TranslateModel model) {
    List<TranslateModel> list = getAllTranslateHistory();
    try {
      int index = list.indexWhere((element) {
        return element.query == model.query && element.to == model.to;
      });
      TranslateModel? translateModel = list[index];
      list.removeAt(index);
      translateModel.count++;
      list.insert(0, translateModel);
      translateHistoryBox?.put(_translateHistoryKey, list);
    } catch (e) {
      list.insert(0, model);
      translateHistoryBox?.put(_translateHistoryKey, list);
    }
  }

  List<TranslateModel> getAllTranslateHistory() {
    List<dynamic> result = translateHistoryBox
        ?.get(_translateHistoryKey, defaultValue: <TranslateModel>[]);
    return result.cast<TranslateModel>();
  }

  void cleanTranslateHistory() {
    translateHistoryBox?.put(_translateHistoryKey, <TranslateModel>[]);
  }

  List<WebBookmarkModel> getAllStarWebUrl() {
    List<dynamic> result = webBox?.get(_webStarKey, defaultValue: <WebBookmarkModel>[]);
    return result.cast<WebBookmarkModel>();
  }

  void addWebStar(String url) {
    List<WebBookmarkModel> list = getAllStarWebUrl();
    String name = findWebsiteInfoFetchByUrl(url)?.title ?? url;
    WebBookmarkModel model = WebBookmarkModel(DateTime.now().millisecondsSinceEpoch.toString(), url, name, time: DateTime.now());
    try {
      list.insert(0, model);
      webBox?.put(_webStarKey, list);
    } catch (e) {
      print(e);
    }
  }

  void deleteWebStar(String url) {
    List<WebBookmarkModel> list = getAllStarWebUrl();
    var result = list.firstWhereOrNull((e) => e.url == url);
    if (result != null) {
      list.remove(result);
      webBox?.put(_webStarKey, list);
    }
    if (Get.isRegistered<BrowserLogic>()) {
      Get.find<BrowserLogic>().checkStar();
    }
  }

  void updateWebStar(WebBookmarkModel model) {
    List<WebBookmarkModel> list = getAllStarWebUrl();
    var result = list.firstWhereOrNull((e) => e.id == model.id);
    if (result != null) {
      list.remove(result);
      list.insert(0, model);
      webBox?.put(_webStarKey, list);
    }
  }

  set webHomePageUrl(String url){
    _set(_webHomePageUrlKey, url);
  }

  String get webHomePageUrl {
    return _get(_webHomePageUrlKey, defaultValue: bingUrl);
  }

  List<WebBookmarkModel> getAllWebHistory() {
    List<dynamic> result = webBox?.get(_webHistoryKey, defaultValue: <WebBookmarkModel>[]);
    return result.cast<WebBookmarkModel>();
  }

  Future<void> addWebHistory(String url) async {
    List<WebBookmarkModel> list = getAllWebHistory();
    String name = (await fetchWebsiteInfo(url))?.title ?? url;
    WebBookmarkModel model = WebBookmarkModel(DateTime.now().millisecondsSinceEpoch.toString(), url, name, time: DateTime.now());
    try {
      list.insert(0, model);
      webBox?.put(_webHistoryKey, list);
    } catch (e) {
      print(e);
    }
  }

  void deleteWebHistory(WebBookmarkModel model) {
    List<WebBookmarkModel> list = getAllWebHistory();
    var result = list.firstWhereOrNull((e) => e.url == model.url && e.time == model.time);
    if (result != null) {
      list.remove(result);
      webBox?.put(_webHistoryKey, list);
    }
    if (Get.isRegistered<BrowserLogic>()) {
      Get.find<BrowserLogic>().checkStar();
    }
  }

  void deleteAllWebHistory() {
    webBox?.delete(_webHistoryKey);
  }

  List<FetchWebsiteInfoModel> getAllFetchWebsiteInfo() {
    List<dynamic> result = fetchWebsiteInfoBox?.get(_fetchWebsiteInfoKey, defaultValue: <FetchWebsiteInfoModel>[]);
    return result.cast<FetchWebsiteInfoModel>();
  }

  void addFetchWebsiteInfo(FetchWebsiteInfoModel model) {
    List<FetchWebsiteInfoModel> list = getAllFetchWebsiteInfo();
    try {
      list.insert(0, model);
      fetchWebsiteInfoBox?.put(_fetchWebsiteInfoKey, list);
    } catch (e) {
      print(e);
    }
  }

  void deleteFetchWebsiteInfo(String url) {
    var list = getAllFetchWebsiteInfo();
    var models = list.where((e) => e.url == url || e.finalUrl == url).toList();
    for(var model in models){
      list.remove(model);
    }
    fetchWebsiteInfoBox?.put(_fetchWebsiteInfoKey, list);
    if (Get.isRegistered<BrowserLogic>()) {
      Get.find<BrowserLogic>().checkStar();
    }
  }

  FetchWebsiteInfoModel? findWebsiteInfoFetchByUrl(String url) {
    var list = getAllFetchWebsiteInfo();
    return list.firstWhereOrNull((e) => e.url == url || e.finalUrl == url);
  }

  void cleanFetchWebsiteInfo() {
    fetchWebsiteInfoBox?.delete(_fetchWebsiteInfoKey);
  }

  List<String> getAllCustomHomepageUrl() {
    List<dynamic> result = _get(_webHomePageCustomUrlListKey, defaultValue: <String>[]);
    return result.cast<String>();
  }

  void setCustomHomepageUrl(String url) {
    var list = getAllCustomHomepageUrl();
    list.add(url);
    _set(_webHomePageCustomUrlListKey, list);
  }

  void deleteCustomHomepageUrl(String url) {
    var list = getAllCustomHomepageUrl();
    list.remove(url);
    _set(_webHomePageCustomUrlListKey, list);
  }
}
